using System.ComponentModel;
using System.Reflection;
using AntDesign;
using BlazorPro.BlazorSize;
using Force.DeepCloner;
using Microsoft.AspNetCore.Components;
using StudentVideo.Client.Services;
using StudentVideo.Shared.Components.CuForm;

namespace StudentVideo.Client.Components;

public partial class CuForm<TFormModel>: ComponentBase, IDisposable where TFormModel : class {
   [Inject] private IMessageService _message { get; set; } = null!;
   [Inject] private IResizeListener _listener { get; set; } = null!;
   [Inject] private JsInteropService _jsInterop { get; set; } = null!;

   /// <summary> 表单数据 </summary>
   [Parameter] public required TFormModel FormModel { get; set; }

   /// <summary> 是否显示 查询 按钮 </summary>
   [Parameter] public bool ShowSearchButton { get; set; } = true;

   /// <summary> 自定义按钮列表 </summary>
   [Parameter] public RenderFragment? CustomsButtons { get; set; }

   /// <summary> 点击查询按钮时触发 </summary>
   [Parameter] public EventCallback<TFormModel> OnSearchHandler { get; set; }
   /// <summary>
   /// 按钮列表 classname
   /// </summary>
   [Parameter] public string? ButtonsClassName { get; set; } = string.Empty;

   private Form<TFormModel> EleForm { get; set; } = null!;
   private ElementReference formBox { get; set; }

   /// <summary>
   /// 单行表单高度
   /// </summary>
   private const double ONE_LINE_HEIGHT = 47;
   /// <summary>
   /// 当前表单高度
   /// </summary>
   private double _moduleHeight { get; set; } = ONE_LINE_HEIGHT;
   /// <summary>
   /// 当前表单父元素高度
   /// </summary>
   private double _boxHeight { get; set; } = ONE_LINE_HEIGHT;

   /// <summary>
   /// 是否显示展开按钮
   /// </summary>
   private bool _showExpandButton { get; set; } = false;
   /// <summary>
   /// 是否展开
   /// </summary>
   private bool _isExpand { get; set; } = false;

   /// <summary> 初始值 </summary>
   public TFormModel? _originFromModule { get; set; }

   private List<PropertyInfo> _properties = [];

   private class SelectItemValue {
      /// <summary>
      /// 显示名称
      /// </summary>
      public required string Label { get; set; }

      public required string Key { get; set; }

      public required string Val { get; set; }
   }

   private Dictionary<string, Dictionary<string, SelectItemValue>> SelectOptionsDic { get; set; } = [];

   protected override void OnInitialized() {
      _properties = [..
         FormModel
            .GetType()
            .GetProperties()
            .Where(p =>
               p is { CanRead: true, CanWrite: true }
               && p.CustomAttributes.Any(e => e.AttributeType == typeof(CuFormMateAttribute))
            )
            .OrderBy(e => e.GetCustomAttribute<CuFormMateAttribute>()!.Order)
      ];

      // 备份原始值
      _originFromModule = FormModel.DeepClone();
   }

   protected override Task OnInitializedAsync() {
      // 获取所有枚举的选项
      foreach (var propertyInfo in _properties) {
         CuFormMateAttribute formMate = propertyInfo.GetCustomAttribute<CuFormMateAttribute>()!;

         if (formMate.FormType == CuFormTypeEnums.Select)
            SelectHandler(propertyInfo);
      }

      return base.OnInitializedAsync();
   }

   protected override async Task OnAfterRenderAsync(bool firstRender) {
      await base.OnAfterRenderAsync(firstRender);

      if (firstRender) {
         _listener.OnResized += EleFormModuleResized;

         await RenderExpandButton();
      }
   }

   /// <summary>
   /// 组件销毁
   /// </summary>
   public void Dispose() {
      _listener.OnResized -= EleFormModuleResized;
      GC.SuppressFinalize(this);
   }

   protected override bool ShouldRender() {
      return base.ShouldRender();
   }

   private async Task RenderExpandButton() {
      var height = await _jsInterop.GetElementProperty<double>($"#{EleForm.Id}", "clientHeight");
      _showExpandButton = height > ONE_LINE_HEIGHT;

      if (_moduleHeight != height)
         _moduleHeight = height;
   }

   private async void EleFormModuleResized(object? sender, BrowserWindowSize e) {
      await RenderExpandButton();

      await InvokeAsync(StateHasChanged);
   }

   // 获取属性值（泛型方法）
   private static T GetPropertyValue<T>(object model, PropertyInfo prop) {
      return (T)prop.GetValue(model)!;
   }

   // 设置属性值（泛型方法）
   private static void SetPropertyValue<T>(object model, PropertyInfo prop, T value) {
      var targetType = prop.PropertyType;
      var convertedValue = Convert.ChangeType(value, targetType);
      prop.SetValue(model, convertedValue);
   }

   /// <summary>
   /// 处理选项框选择列表
   /// </summary>
   /// <param name="info"></param>
   /// <exception cref="Exception"></exception>
   private void SelectHandler(PropertyInfo info) {
      var mate = info.GetCustomAttribute<CuFormMateSelectAttribute>()
         ?? throw new ArgumentException($"In the CuFormMate attribute of {info?.DeclaringType?.Name}.{info?.Name}, CuFormMateSelectAttribute must be set when FormType is Select");

      Dictionary<string, SelectItemValue> pairs = [];

      if (mate.SelectType == null && mate.SelectUri == null)
         throw new ArgumentException($"In the CuFormMate attribute of {info?.DeclaringType?.Name}.{info?.Name}, either SelectType or SelectUri must be specified when FormType is set to Select.");

      if (mate.SelectUri != null) {
         pairs = GetSelectItemByUri(mate.SelectUri, info);
      } else if (mate.SelectType != null) {
         pairs = GetSelectItemByEnum(mate.SelectType, info);
      }

      SelectOptionsDic.Add(info.Name, pairs);
   }

   private static Dictionary<string, SelectItemValue> GetSelectItemByUri(string uri, PropertyInfo info) {
      // TODO 通过远程地址获取单选框内容列表

      return [];
   }

   private static Dictionary<string, SelectItemValue> GetSelectItemByEnum(Type type, PropertyInfo info) {
      if (type.IsEnum == false)
         throw new ArgumentException($"In the CuFormMate attribute of {info!.DeclaringType!.Name}.{info.Name}, SelectType must be an Enum.");

      Dictionary<string, SelectItemValue> dict = [];

      foreach (Enum value in Enum.GetValues(type)) {
         var name = Enum.GetName(type, value);

         if (name == null)
            continue;

         var field = type.GetField(name);
         var attribute = field?.GetCustomAttribute<DescriptionAttribute>();

         var label = name;

         if (attribute != null)
            label = attribute.Description;

         SelectItemValue pairValue = new() {
            Label = label,
            Key = name,
            Val = value.ToString(),
         };
         dict.Add(name, pairValue);
      }

      return dict;
   }

   public void SearchHandler() {
      // 验证 form
      if (EleForm == null) {
         _message.Error("查询失败");
         return;
      }

      if (EleForm.Validate() == false) {
         _message.Error("验证失败");
      }

      OnSearchHandler.InvokeAsync(FormModel);
   }

   private void ChangeExpandStatus() {
      if (_isExpand) {
         _isExpand = false;
         _boxHeight = ONE_LINE_HEIGHT;
      } else {
         _isExpand = true;
         _boxHeight = _moduleHeight + 15;
      }
   }

   private string[] GetHelps(CuFormMateAttribute mate, PropertyInfo info) {
      var helps = mate.Helps;

      if (helps == null)
         return ["开始时间", "结束时间"];

      if (helps.Length < 2)
         throw new ArgumentException($"In the CuFormMate attribute of {info.PropertyType.Name}.{info.Name}, Helps length must be >= 2.");

      return helps;
   }
}
